#include "flash.h"
#include "stm32f4xx_hal_flash.h"
#include "stm32f4xx_hal_flash_ex.h"
#include "stm32f4xx_hal_flash_ramfunc.h"
#include <string.h>
#define FLASH_TYPEPROGRAM_FLASHWORD  0x01U        /*!< Program a flash word (256-bit) at a specified address */

/**
 * @Function: TE_FLASH_STATUS FlashWrite(uint32_t startAddr, uint8_t *data,uint32_t len)
 * @Description: Program the user Flash area word by word
 * @Input : startAddr: Write start address, *data: Data pointer to write data, len: the length of the data
 * @Output: None
 * @Return: Return function status ->E_FLASH_OK: Erase successful ,otherwise : failed
 * @Others: None
 */
TE_FLASH_STATUS FlashWrite(uint32_t startAddr, uint8_t *data,uint32_t len)
{
	
	uint32_t address     = startAddr;
	uint32_t i           = 0;
	uint32_t endAddress  = startAddr + len;
	uint8_t *pData      = data;
	
	if(startAddr> ADDR_FLASH_SECTOR_0_BANK1 && (startAddr + len-1 > FLASH_END_ADDR))
	{
		return E_FLASH_ERROR;
	}


  /* Program the user Flash area word by word
    (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/


	/* Enter critical region */
	//taskENTER_CRITICAL();
	/* Unlock the Flash to enable the flash control register access *************/
	HAL_FLASH_Unlock();

	while(address < endAddress)
	{
		if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address,pData[i]) != HAL_OK)
		{
			return E_FLASH_ERROR;
		}
		address = address + 1; /* increment for the next Flash word-- 8 word = 32 bytes*/
		i       = i + 1;
	}
	__DSB();
	/* Lock the Flash to disable the flash control register access (recommended
	 to protect the FLASH memory against possible unwanted operation) *********/
	HAL_FLASH_Lock();
		/* Enter critical region */
	//taskEXIT_CRITICAL();
	return E_FLASH_OK;
}

/**
 * @Function: TE_FLASH_STATUS FlashRead(uint32_t startAddr, uint8_t *buff,uint32_t len)
 * @Description: Read data from flash
 * @Input : startAddr: Start address of reading data, *data: Data pointer to read data, len: the length of the data
 * @Output: None
 * @Return: Return function status ->E_FLASH_OK: Erase successful ,otherwise : failed
 * @Others: None
 */
TE_FLASH_STATUS FlashRead(uint32_t startAddr, uint8_t *buff,uint32_t len)
{
	uint32_t endAddress  = startAddr + len;
	__IO uint32_t *pData = (uint32_t*)buff;
	
	uint32_t Address     = startAddr;
	uint32_t i           = 0;	
	
	if(endAddress-1 > FLASH_END_ADDR)
	{
		return E_FLASH_ERROR;
	}

	while(Address < endAddress)
	{
		pData[i++] = *(__IO uint32_t *)Address;
		__DSB();
		 Address +=4;
	}
	return E_FLASH_OK;
}


TE_FLASH_STATUS FlashErase(TE_FLASH_SECTOR sector,uint8_t sector_num)
{
	uint32_t SECTORError = 0;
	uint32_t FirstSector = 0, NbOfSectors = 0;
	/*Variable used for Erase procedure*/
	FLASH_EraseInitTypeDef EraseInitStruct;
	
	
	/* Unlock the Flash to enable the flash control register access *************/
	HAL_FLASH_Unlock();
	  /* Get the 1st sector to erase */
	FirstSector = sector;
	/* Get the number of sector to erase from 1st sector*/
	NbOfSectors = sector_num;

	/* Fill EraseInit structure*/
	EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;
	EraseInitStruct.VoltageRange  = FLASH_VOLTAGE_RANGE_3;
	EraseInitStruct.Banks         = FLASH_BANK_1;
	EraseInitStruct.Sector        = FirstSector;
	EraseInitStruct.NbSectors     = NbOfSectors;

	if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
	{
	/*
	  Error occurred while sector erase.
	  User can add here some code to deal with this error.
	  SECTORError will contain the faulty sector and then to know the code error on this sector,
	  user can call function 'HAL_FLASH_GetError()'
	*/
		return E_FLASH_ERROR;
	}


	/* Lock the Flash to disable the flash control register access (recommended
	to protect the FLASH memory against possible unwanted operation) *********/
	HAL_FLASH_Lock();
	/* Enter critical region */
	//taskEXIT_CRITICAL();
	return E_FLASH_OK;
}

/**
 * @Function: void FlashTest(void)
 * @Description: This function is only used to test flash reading and writing
 * @Input : None
 * @Output: None
 * @Return: None
 * @Others: None
 */
void FlashTest(void)
{
#define FLASH_PARA_ADDR ADDR_FLASH_SECTOR_11_BANK1	
  uint8_t data[1024] = {0};
	uint32_t i = 0;
	FlashErase(E_FLASH_SECTOR_11,1);
	FlashRead(FLASH_PARA_ADDR,(uint8_t *)data,sizeof(data));
	
	for(i = 0; i < sizeof(data); i++)
	{
		data[i] = i;
	}
	//memset(data,0x5A,sizeof(data));
	FlashWrite(FLASH_PARA_ADDR,(uint8_t *)data,sizeof(data));

	FlashRead(FLASH_PARA_ADDR,(uint8_t *)data,sizeof(data));
}

